﻿/**
 * Peter
 * Created by: Peter Development Team
 *    http://peter.codeplex.com/
 * 
 * GNU General Public License version 2 (GPLv2)
 *    http://peter.codeplex.com/license
 *
 *  This code is provided on an AS IS basis, with no WARRANTIES,
 *  CONDITIONS or GUARANTEES of any kind.
 *
 **/

using System;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Peter.Common;
using Peter.Common.Utilities;

namespace Peter.NodeJs
{
   /// <summary>
   /// Node js support.
   /// </summary>
   [Export (typeof (INodeJs))]
   [PartCreationPolicy (CreationPolicy.Shared)]
   public class NodeJs : INodeJs
   {
      private readonly CommandPrompt m_Cmd;
      private readonly string m_NodeJsDir;

      /// <summary>
      /// Initializes a new node js object.
      /// </summary>
      public NodeJs ()
      {
         this.m_NodeJsDir = Path.Combine (CommonUtilities.GetAssemblyDirectory (), "nodejs") + "\\";
         var appData = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
         var path = appData + "\\npm;" + this.m_NodeJsDir + ";" + Environment.GetEnvironmentVariable ("Path");
         Environment.SetEnvironmentVariable ("Path", path, EnvironmentVariableTarget.Process);
         if (Directory.Exists (this.m_NodeJsDir))
         {
            this.m_Cmd = new CommandPrompt ();
            this.m_Cmd.Initialize ();
            this.m_Cmd.OutputRecieved += this.OnCmdOutput;
            this.m_Cmd.ChangeDirectory (this.m_NodeJsDir);
         }
      }

      /// <summary>
      /// Occurs when the command line for node js receives any output.
      /// </summary>
      /// <param name="message"></param>
      /// <param name="iserror"></param>
      private void OnCmdOutput (string message, bool iserror)
      {
         
      }

      /// <summary>
      /// Gets the value of the given congif variable.
      /// </summary>
      /// <param name="variable">Config variable to get value for.</param>
      /// <returns>The value of the given variable.</returns>
      public async Task <string> GetNpmConfig (string variable)
      {
         return await RunNpmCommand ("config get " + variable);
      }

      /// <summary>
      /// Sets the value of the given config variable
      /// </summary>
      /// <param name="variable">Variable to set value for.</param>
      /// <param name="value">Value to set.</param>
      public async void SetNpmConfig (string variable, string value)
      {
         await RunNpmCommand ("config set " + variable + " " + value);
      }

      /// <summary>
      /// A thread task to run npm commands.
      /// </summary>
      /// <param name="command"></param>
      /// <returns></returns>
      private async Task <string> RunNpmCommand (string command)
      {
         var value = string.Empty;
         var error = string.Empty;
         await Task.Run (() =>
         {
            var process = new Process
            {
               StartInfo =
               {
                  FileName = "npm.cmd",
                  Arguments = command,
                  UseShellExecute = false,
                  RedirectStandardOutput = true,
                  RedirectStandardError = true,
                  CreateNoWindow = true,
                  WindowStyle = ProcessWindowStyle.Hidden,
                  WorkingDirectory = this.m_NodeJsDir
               }
            };
            process.Start ();
            process.WaitForExit ();
            value = process.StandardOutput.ReadToEnd ().Trim ();
            error = process.StandardError.ReadToEnd ().Trim ();
            process.Dispose ();
         });
         return !string.IsNullOrWhiteSpace (error) ? error : value;
      }
   }
}
